{
                match (left, right) {
                    (BasicValueEnum::IntValue(l), BasicValueEnum::IntValue(r)) => {
                        let (l_norm, r_norm) = self.normalize_int_operands(l, r)?;
                        Ok(self.builder.build_int_add(l_norm, r_norm, "add")?.into())
                    }
                    (BasicValueEnum::FloatValue(l), BasicValueEnum::FloatValue(r)) => {
                        Ok(self.builder.build_float_add(l, r, "fadd")?.into())
                    }
                    (BasicValueEnum::PointerValue(l), BasicValueEnum::PointerValue(r)) => {
                        // String concatenation: s1 + s2
                        // Both operands should be i8* (string pointers)

                        // Declare C string functions (only once)
                        let i8_ptr_type = self
                            .context
                            .i8_type()
                            .ptr_type(inkwell::AddressSpace::default());
                        let i32_type = self.context.i32_type();
                        let i64_type = self.context.i64_type();

                        // strlen: i32 strlen(i8*)  (note: uses i32, not i64)
                        let strlen_fn_type = i32_type.fn_type(&[i8_ptr_type.into()], false);
                        let strlen_fn = if let Some(func) = self.module.get_function("strlen") {
                            func
                        } else {
                            self.module.add_function("strlen", strlen_fn_type, None)
                        };

                        // malloc: i8* malloc(i64)
                        let malloc_fn_type = i8_ptr_type.fn_type(&[i64_type.into()], false);
                        let malloc_fn = if let Some(func) = self.module.get_function("malloc") {
                            func
                        } else {
                            self.module.add_function("malloc", malloc_fn_type, None)
                        };

                        // strcpy: i8* strcpy(i8* dst, i8* src)
                        let strcpy_fn_type =
                            i8_ptr_type.fn_type(&[i8_ptr_type.into(), i8_ptr_type.into()], false);
                        let strcpy_fn = if let Some(func) = self.module.get_function("strcpy") {
                            func
                        } else {
                            self.module.add_function("strcpy", strcpy_fn_type, None)
                        };

                        // strcat: i8* strcat(i8* dst, i8* src)
                        let strcat_fn_type =
                            i8_ptr_type.fn_type(&[i8_ptr_type.into(), i8_ptr_type.into()], false);
                        let strcat_fn = if let Some(func) = self.module.get_function("strcat") {
                            func
                        } else {
                            self.module.add_function("strcat", strcat_fn_type, None)
                        };

                        // Calculate string lengths
                        let len1 = self
                            .builder
                            .build_call(strlen_fn, &[l.into()], "len1")?
                            .try_as_basic_value()
                            .left()
                            .unwrap()
                            .into_int_value();
                        let len2 = self
                            .builder
                            .build_call(strlen_fn, &[r.into()], "len2")?
                            .try_as_basic_value()
                            .left()
                            .unwrap()
                            .into_int_value();

                        // Calculate total length: len1 + len2 + 1 (for null terminator)
                        let total_len = self.builder.build_int_add(len1, len2, "total_len")?;
                        let total_len_with_null = self.builder.build_int_add(
                            total_len,
                            i32_type.const_int(1, false),
                            "total_len_with_null",
                        )?;

                        // Convert i32 to i64 for malloc (which expects i64)
                        let total_len_i64 = self.builder.build_int_z_extend(
                            total_len_with_null,
                            i64_type,
                            "total_len_i64",
                        )?;

                        // Allocate new memory
                        let new_str = self
                            .builder
                            .build_call(malloc_fn, &[total_len_i64.into()], "new_str")?
                            .try_as_basic_value()
                            .left()
                            .unwrap()
                            .into_pointer_value();

                        // Copy first string: strcpy(new_str, s1)
                        let _ = self.builder.build_call(
                            strcpy_fn,
                            &[new_str.into(), l.into()],
                            "strcpy_call",
                        )?;

                        // Concatenate second string: strcat(new_str, s2)
                        let _ = self.builder.build_call(
                            strcat_fn,
                            &[new_str.into(), r.into()],
                            "strcat_call",
                        )?;

                        Ok(new_str.into())
                    }
                    _ => Err(CompilerError::internal("Type mismatch in addition")),
                }
            }
